package com.paradogs.gs.misc;

import com.google.common.base.Function;
import com.paradogs.gs.modules.Player;
import com.paradogs.gs.modules.OwnerSyncData;
import com.paradogs.gs.utils.PlayerUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.BiConsumer;

/**
 * @author: yumi
 * @date: 2024/10/16  11:19
 * @Description: 状态同步管理器
 */
public class SyncDataUpdater {

    // 待同步集合
    private static final Map<Long, OwnerSyncData> syncSessionMap = new LinkedHashMap<>();
    private static final Map<String, Field> syncDataFieldCache = new HashMap<>(); // SyncData 反射 Field 缓存

    static {
        // 缓存 SyncData 反射
        for (Field field : OwnerSyncData.class.getDeclaredFields()) {
            field.setAccessible(true);
            syncDataFieldCache.put(field.getName(), field);
        }

    }

    /** 提交玩家数据变化更新，会在一次消息处理后同步给玩家 */
    public static void commit(Long id, BaseMgrEntity uData) {
        if (uData == null) { return; }
        try {
            // 将更新数据设置（覆盖）到 SyncData 上
            String name = uData.getClass().getSimpleName();
            Field field = syncDataFieldCache.get(name.substring(0, 1).toLowerCase()
                    + name.substring(1));
            if (field == null) { return; }
            if (!syncSessionMap.containsKey(id)) {
                syncSessionMap.put(id, new OwnerSyncData());
            }
            OwnerSyncData ownerSyncData = syncSessionMap.get(id);
            field.set(ownerSyncData, uData);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void commit(Long id, BaseMgrMultiEntity uData) {
        try {
            // 将更新数据设置（覆盖）到 SyncData 上
            String name = uData.getClass().getSimpleName();
            Field field = syncDataFieldCache.get(name.substring(0, 1).toLowerCase()
                    + name.substring(1) + "s");
            if (field == null) { return; }
            if (!syncSessionMap.containsKey(id)) {
                syncSessionMap.put(id, new OwnerSyncData());
            }
            OwnerSyncData ownerSyncData = syncSessionMap.get(id);
            /**
             * !!! @Data 修饰的实体类，equals 重写并且默认 @EqualsAndHashCode(callSuper = false)，会导致判断为相同
             * 需要在实体类上添加 @EqualsAndHashCode(callSuper = true)
             */
            Set<BaseMgrMultiEntity> set = (Set<BaseMgrMultiEntity>) field.get(ownerSyncData);
            if (set == null) {
                set = new LinkedHashSet<>();
                field.set(ownerSyncData, set);
            }
            set.add(uData);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** 进行自动同步 */
    public static void autoSync() {
        if (syncSessionMap.isEmpty()) { return; }
        for (Map.Entry<Long, OwnerSyncData> entry : syncSessionMap.entrySet()) {
            Long uid = entry.getKey();
            OwnerSyncData ownerSyncData = entry.getValue();
            Player player = PlayerUtils.getPlayer(uid);
            if (player != null) {
                player._netMgr().syncOwner(ownerSyncData);
            }
        }
    }

    /** 清空待同步集合 */
    public static void clear() {
        syncSessionMap.clear();
    }

    public static <E extends BaseMgrMultiEntity, T> void commit(
            Function<OwnerSyncData, Set<E>> ownerSyncDataGetter, BiConsumer<OwnerSyncData, Set<E>> ownerSyncDataSetter
            , Class<E> dataClass, Long id, Long aid, BiConsumer<E,T> consumer, T val) {
        try {
            if (!syncSessionMap.containsKey(id)) {
                syncSessionMap.put(id, new OwnerSyncData());
            }
            // 从 OwnerSyncData 中找出 Set
            OwnerSyncData ownerSyncData = syncSessionMap.get(id);
            Set<E> set = ownerSyncDataGetter.apply(ownerSyncData);
            if (set == null) {
                set = new LinkedHashSet<>();
                ownerSyncDataSetter.accept(ownerSyncData, set);
            }
            // 从 Set 中找出 data
            E data = null;
            for (E e : set) {
                if (e.getId().equals(aid)) {
                    data = e;
                    break;
                }
            }
            if (data == null) {
                // 新增 data
                data = dataClass.newInstance();
                data.setUid(id);
                data.setId(aid);
                set.add(data);
            }

            // 赋值
            consumer.accept(data, val);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
